import sys
import json
import yaml

from util import lookup

def load(filename):
  f=open(filename, 'r')
  if '.yaml' in filename:
    y=yaml.load(f)
  else:
    y=json.load(f)
  f.close()
  return y

def format(system, userlib, fname):
  f=lookup(system, userlib, {}, {}, fname)
  return formatMethod(system, userlib, fname, f, '')

def formatMethod(system, userlib, fname, f, indent):
  ftype=f['type']
  s=''

  if ftype=='method':
    s=s+indent+fname+'('+formatParams(f['params'])+'):'+"\n"
    s=s+formatPrivate(system, userlib, f, indent)
    s=s+formatCode(system, userlib, f['code'], indent+'  ')

  return s

def formatParams(params):
  s=''

  if len(params)==0:
    return ''

  for param in params:
    s=s+param+', '

  return s[:-2]

def formatPrivate(system, userlib, f, indent):
  s=''

  for pf in f:
    if pf!='type' and pf!='params' and pf!='code':
      s=s+indent+formatMethod(system, userlib, pf, f[pf], indent+'  ')+"\n"

  return s

def formatArgs(system, userlib, args):
  s=''

  if len(args)==0:
    return ''

  for value in args:
    s=s+formatArg(system, userlib, value)+', '

  return s[:-2]

def formatFunc(system, userlib, code):
  name=code[1][0]
  args=code[1][1]
  l=[]

  if hasView(system, userlib, name):
    if name in system:
      f=system[name]
    else:
      f=userlib[name]
    return formatView(system, userlib, f['view'], args)
  else:
    return [{'line': name+'('+formatArgs(system, userlib, args)+')', 'children': None}]

def hasBlock(view):
  for value in view:
    if value[0]=='block':
      return True

  return False

def formatCode(system, userlib, code, indent):
  s=''
  typ=code[0]

  if typ=='func':
    list=formatFunc(system, userlib, code)

  s=formatTree(list, indent)

  return s

def hasView(system, userlib, name):
  if name in system:
    f=system[name]
  elif name in userlib:
    f=userlib[name]
  else:
    return False

  return 'view' in f

def formatView(system, userlib, view, args):
  if len(args)==0:
    return []

  if hasBlock(view):
    return formatBlockView(system, userlib, view, args)
  else:
    return formatInlineView(system, userlib, view, args)

def formatInlineView(system, userlib, view, args):
  s=''

  for value in view:
    if value[0]=='func':
      s=s+value[1]
    elif value[0]=='symref':
      index=value[1]
      value=args[index]
      s=s+formatArg(system, userlib, value)
    elif value[0]=='sugar':
      s=s+value[1]

    s=s+' '

  return [{'line': s[:-1], 'children': None}]

def formatBlockView(system, userlib, view, args):
  lines=[]
  current={'line': '', 'children': None}

  for value in view:
    if value[0]=='func':
      current['line']=current['line']+value[1]+" "
    elif value[0]=='sugar':
      current['line']=current['line']+value[1]+" "
    elif value[0]=='symref':
      index=value[1]
      value=args[index]
      current['line']=current['line']+formatArg(system, userlib, value)+" "
    elif value[0]=='block':
      index=value[1]
      value=args[index][1]['code']
      current['children']=formatFunc(system, userlib, value)
      lines.append(current)
      current={'line': '', 'children': None}

  if current['line']!='' or current['children']!=None:
    lines.append(current)

  return lines

def escape(s):
  if "\n" in s:
    return s.replace("\n", "\\n")
  else:
    return s

def formatArg(system, userlib, arg):
  if arg[0]=='literal':
    if type(arg[1])==str:
      return "'"+escape(arg[1])+"'"
    elif type(arg[1])==list:
      s=', '.join([formatArg(system, userlib, item) for item in arg[1]])
      return '['+s+']'
    else:
      return str(arg[1])
  elif arg[0]=='symdef':
    return arg[1]
  elif arg[0]=='func':
    return formatFunc(system, userlib, arg)[0]['line']
  elif arg[0]=='symref':
    return str(arg[1])

def formatTree(list, indent):
  s=''

  for tree in list:
    s=s+indent+tree['line']+"\n"
    if tree['children']:
      s=s+formatTree(tree['children'], indent+'  ')

  return s

if __name__=='__main__':
  system=load('system.json')
  userlib=load(sys.argv[1])

  print(format(system, userlib, sys.argv[2]))
